#include "ffmpeg_videoreceive.h"
#include <QDateTime>
//#define ENABLE_VAAPI  //使能硬件加速




FFMPEG_VideoReceive::FFMPEG_VideoReceive()
{

   this->FFMPEG_Init();


}

void FFMPEG_VideoReceive::FFMPEG_Init()
{
   //**1.打开文件***//
    const char* input_path = "/home/ubuntu/桌面/test.mp4";
   int ret  = avformat_open_input(&fmt_ctx,input_path,nullptr,nullptr);
   if(ret < 0)
   {
       qDebug()<<"视频文件打开失败="<<ret;
   }
   //**2.获取输入流信息***//
   ret = avformat_find_stream_info(fmt_ctx,nullptr);
   if(ret < 0)
   {
      qDebug()<<"找不到流="<<ret;
   }
    //**3.获取视频流信息***//

    int video_index = av_find_best_stream(fmt_ctx,AVMEDIA_TYPE_VIDEO,
                                          -1,-1,nullptr,0);

    if(video_index < 0)
     {
         qDebug()<<"未找到有效码流"<<video_index;
         return;
     }
     else
     {
         qDebug()<<"找到视频序号"<<video_index;
     }


     #ifdef ENABLE_VAAPI
     //硬件解码部分
     enum AVHWDeviceType type;
     const char* hwdevice_name="vaapi";
     type = av_hwdevice_find_type_by_name(hwdevice_name);

     if (type == AV_HWDEVICE_TYPE_NONE) {
         qDebug()<<"硬件"<<hwdevice_name<<"不被支持";
         while ((type = av_hwdevice_iterate_types(type))
                != AV_HWDEVICE_TYPE_NONE)
             qDebug()<<"仅支持"<<av_hwdevice_get_type_name(type);
         return ;
     }
     else
     {
      qDebug()<<"支持"<<av_hwdevice_get_type_name(type);
     }

    #endif
       //**4.创建解码器上下文***//

      AVCodecContext * codecCtx =  avcodec_alloc_context3(NULL);
      if(codecCtx == NULL)
         {
             avcodec_free_context(&codecCtx);
             qDebug()<<"编码器上下文创建失败";
             return;
         }

      //**5.拷贝参数到编码器***//

       ret = avcodec_parameters_to_context(codecCtx, fmt_ctx->streams[video_index]->codecpar);
       if(ret < 0)
       {
           qDebug()<<"编码器参数拷贝失败"<<ret;
           return;
       }
       //**6.生成编码器***//
       const AVCodec * avcodec = avcodec_find_decoder(codecCtx->codec_id);
       if(avcodec == NULL)
       {
           qDebug()<<"寻找匹配编码器失败"<<codecCtx->codec_id;
           return;
       }

        #ifdef ENABLE_VAAPI
        //硬件解码部分
       if (av_hwdevice_ctx_create(&hw_device_ctx, type,
                                  nullptr, nullptr, 0) < 0)
       {
              qDebug()<<"硬件设备创建失败";
              avformat_close_input(&fmt_ctx);
              avcodec_free_context(&codecCtx);
              return;
       }
       codecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx);

       #endif




        //**7.打开编码器***//
       ret = avcodec_open2(codecCtx, avcodec, NULL);
        if(ret<0)
        {
            qDebug()<<"编码器打开失败"<<ret;

            avformat_close_input(&fmt_ctx);
            avcodec_free_context(&codecCtx);
            av_buffer_unref(&hw_device_ctx);
            return;
        }

        av_init_packet(&packet); //初始化packet
        frame = av_frame_alloc(); //分配一帧

        double start_time = QDateTime::currentDateTime().toSecsSinceEpoch();
         //**8.从packet里面解析***//
        while(av_read_frame(fmt_ctx,&packet)==0)
        {
            if(packet.stream_index==video_index) //如果序号对得上
            {
                //**9.发送给编码器***//
               ret = avcodec_send_packet(codecCtx,&packet);
                if(ret != 0)
                {
                   qDebug()<< "发送给编码器失败";
                   av_packet_unref(&packet);
                   return;
                }
                 //**10.从编码器获取一帧***//
                while(avcodec_receive_frame(codecCtx,frame)==0)
                {
                    if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
                    {
                       break;
                    }
                    else if(ret < 0)
                    {
                        return;
                    }

                    qDebug()<<"解开一帧";
                }
            }

            av_packet_unref(&packet);


        }
         double end_time = QDateTime::currentDateTime().toSecsSinceEpoch();
         qDebug()<<"解码花费"<<end_time-start_time<<"s";

         // 释放资源
         av_frame_free(&frame);
         avcodec_free_context(&codecCtx);
         av_buffer_unref(&hw_device_ctx);
         avformat_close_input(&fmt_ctx);

}
